package com.wei.czz.framework.game.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.dto.game.GamePrizeDto;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.game.GameEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.game.GamePo;
import com.wei.czz.common.po.game.GamePrizePo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.handler.redis.RedisSetHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.common.vo.game.DeleteGamePrizeVo;
import com.wei.czz.common.vo.game.GamePrizeFormVo;
import com.wei.czz.common.vo.game.GamePrizeVo;
import com.wei.czz.common.vo.game.UpdateGamePrizeStatusVo;
import com.wei.czz.framework.admin.service.UserService;
import com.wei.czz.framework.common.service.AsyncService;
import com.wei.czz.framework.game.service.GamePrizeFlowService;
import com.wei.czz.framework.game.service.GameService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.wei.czz.framework.game.dao.GamePrizeDao;
import com.wei.czz.framework.game.entity.GamePrizeEntity;
import com.wei.czz.framework.game.service.GamePrizeService;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2023-03-16 11:36:29
 * className: GamePrizeServiceImpl 游戏奖品请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("gamePrizeService")
@AllArgsConstructor
public class GamePrizeServiceImpl extends ServiceImpl<GamePrizeDao, GamePrizeEntity> implements GamePrizeService {

    private static final Logger log = LoggerFactory.getLogger(GamePrizeServiceImpl.class);

    private final UserService userService;

    private final GameService gameService;

    private final GamePrizeFlowService gamePrizeFlowService;

    private final RedisHashHandler redisHashHandler;

    private final RedisHandler redisHandler;

    private final RedisSetHandler redisSetHandler;

    private final AsyncService asyncService;

    @Override
    public void saveGamePrize(GamePrizeVo gamePrizeVo) {

        // 判断是否允许插入
        GamePo gamePo = gameService.getGamePo(gamePrizeVo.getGameId());
        if (gamePo.getStatus().equals(CommonEnum.ZERO.getValue())) {
            log.warn("游戏已经开始，不可以再添加新的奖品。 gameId={} {}", gamePrizeVo.getGameId(), gamePo);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏已经开始，不可以再添加新的奖品。");
        }

        // 获取正在保存游戏奖品的用户主键
        Long optUserId = SecurityUtils.getUserId();
        Date date = new Date();

        GamePrizeEntity gamePrize = new GamePrizeEntity();
        // 属性赋值
        gamePrize.setGameId(gamePrizeVo.getGameId())
                .setPrizeName(gamePrizeVo.getPrizeName())
                .setPrizeValue(gamePrizeVo.getPrizeValue())
                .setPrizeTotalNum(gamePrizeVo.getPrizeTotalNum())
                .setPrizeUseNum(0)
                .setProbability(gamePrizeVo.getProbability())
                .setSort(gamePrizeVo.getSort())
                .setStatus(CommonEnum.ZERO.getValue())
                .setDeleteFlag(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(optUserId)
                .setCreateTime(date)
                .setCreateUser(optUserId)
                .setRemark(gamePrizeVo.getRemark());
        // 插入数据
        baseMapper.insert(gamePrize);
        log.info("插入游戏奖品数据完成");

        asyncService.execute(() -> {
            // 记录新增奖品流水
            String title = "添加游戏奖品";
            String content = "奖品名称【" + gamePrize.getPrizeName() + "】" +
                    "具体奖品【" + gamePrize.getPrizeValue() + '】' +
                    "奖品总数【" + gamePrize.getPrizeTotalNum() + '】' +
                    "中奖概率【" + gamePrize.getProbability() + '】' +
                    "排序等级【" + gamePrize.getSort() + '】';
            // 记录奖品流水
            gamePrizeFlowService.saveGamePrizeFlow(gamePrize.getId(), title, content, optUserId);
        });
    }

    @Override
    public void initGamePrizePool(Long gameId) {
        // 判断是否允许初始化奖品池
        GamePo gamePo = gameService.getGamePo(gameId);
        if (gamePo.getStatus().equals(CommonEnum.ZERO.getValue())) {
            log.warn("游戏已经开始，不允许初始化奖品池。 gameId={} {}", gameId, gamePo);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏已经开始，不允许初始化奖品池。");
        }

        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gamePrizeLambdaQueryWrapper.select(GamePrizeEntity::getId, GamePrizeEntity::getPrizeTotalNum,
                GamePrizeEntity::getPrizeUseNum, GamePrizeEntity::getProbability);
        // 匹配条件
        gamePrizeLambdaQueryWrapper.eq(GamePrizeEntity::getGameId, gameId)
                .eq(GamePrizeEntity::getStatus, CommonEnum.ZERO.getValue())
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        List<GamePrizeEntity> gamePrizeList = baseMapper.selectList(gamePrizeLambdaQueryWrapper);
        if (gamePrizeList.isEmpty()) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏奖品数据为空，初始化失败");
        }

        // 所有奖品总概率
        Integer totalProbability = gamePrizeList.stream().map(GamePrizeEntity::getProbability)
                .reduce(0, Integer::sum);
        log.info("游戏（{}）所有奖品总概率为：{}", gameId, totalProbability);
        if (totalProbability % 10 != 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "所有游戏奖品的总中奖概率必须为10的整数倍数值");
        }
        Map<String, Integer> gamePrizeMap = new HashMap<>();
        List<GamePrizePo> gamePrizePoList = new ArrayList<>();
        for (GamePrizeEntity gamePrize : gamePrizeList) {
            if (gamePrize.getPrizeTotalNum().compareTo(gamePrize.getPrizeUseNum()) <= 0) {
                continue;
            }
            // 设置奖品对应的剩余数量
            gamePrizeMap.put(gamePrize.getId().toString(), gamePrize.getPrizeTotalNum() - gamePrize.getPrizeUseNum());
            // 生成游戏奖品池列表
            int length = gamePrize.getProbability();
            for (int i = 0; i < length; i++) {
                gamePrizePoList.add(new GamePrizePo(gamePrize.getId(), i));
            }
        }
        // 添加游戏奖品池缓存
        String redisKey = RedisConstant.GAME_PRIZE_SET + gameId;
        // 删除原来的游戏奖品池缓存
        redisHandler.delete(redisKey);
        // 删除游戏奖品剩余数量缓存
        redisHandler.delete(RedisConstant.GAME_PRIZE_MAP);
        if (gamePrizePoList.isEmpty()) {
            log.info("所有奖品已经发放完毕，无需再初始化奖品池");
        } else {
            // 游戏奖品池初始化
            gameService.updatePrizePoolFlag(gameId, GameEnum.INIT_PRIZE_POOL.getValue(), SecurityUtils.getUserId());

            // 增加游戏奖品剩余数量缓存
            redisHashHandler.putAll(RedisConstant.GAME_PRIZE_MAP, gamePrizeMap);
            // 增加游戏奖品池缓存
            redisSetHandler.add(redisKey, gamePrizePoList);
        }
    }

    @Override
    public PageDto<GamePrizeDto> pageGamePrizeList(GamePrizeFormVo gamePrizeFormVo) {

        // 分页对象构造
        Page<GamePrizeEntity> page = PageQuery.initPage(gamePrizeFormVo);

        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gamePrizeLambdaQueryWrapper.select(GamePrizeEntity::getId, GamePrizeEntity::getPrizeName, GamePrizeEntity::getPrizeValue,
                GamePrizeEntity::getPrizeTotalNum, GamePrizeEntity::getPrizeUseNum, GamePrizeEntity::getProbability,
                GamePrizeEntity::getSort, GamePrizeEntity::getStatus, GamePrizeEntity::getCreateTime, GamePrizeEntity::getCreateUser,
                GamePrizeEntity::getRemark);
        // 条件匹配
        gamePrizeLambdaQueryWrapper.eq(GamePrizeEntity::getGameId, gamePrizeFormVo.getGameId())
                .like(StringUtils.isNotBlank(gamePrizeFormVo.getWord()), GamePrizeEntity::getPrizeName, gamePrizeFormVo.getWord())
                .eq(Objects.nonNull(gamePrizeFormVo.getStatus()), GamePrizeEntity::getStatus, gamePrizeFormVo.getStatus())
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        baseMapper.selectPage(page, gamePrizeLambdaQueryWrapper);

        List<GamePrizeEntity> gamePrizeList = page.getRecords();
        if (gamePrizeList.isEmpty()) {
            return new PageDto<>(Collections.emptyList(), page.getTotal(), gamePrizeFormVo.getPage(), gamePrizeFormVo.getLimit());
        }

        Set<Long> userIdSet = gamePrizeList.stream().map(GamePrizeEntity::getCreateUser).collect(Collectors.toSet());
        Map<Long, String> userNameMap = userService.getNameMap(userIdSet, Function.identity());
        // 数据封装
        List<GamePrizeDto> gamePrizeDtoList = gamePrizeList.stream()
                .map(gamePrize -> {
                    GamePrizeDto gamePrizeDto = new GamePrizeDto();
                    // 属性值复制
                    BeanUtils.copyProperties(gamePrize, gamePrizeDto);

                    gamePrizeDto.setId(gamePrize.getId().toString())
                            .setCreateUser(userNameMap.get(gamePrize.getCreateUser()));

                    return gamePrizeDto;
                }).collect(Collectors.toList());

        return new PageDto<>(gamePrizeDtoList, page.getTotal(), gamePrizeFormVo.getPage(), gamePrizeFormVo.getLimit());
    }

    @Override
    public List<GamePrizeEntity> getGamePrizeList(List<Long> gameIdList) {
        if (CollectionUtils.isEmpty(gameIdList)) {
            log.info("游戏主键列表为空");
            return Collections.emptyList();
        }
        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配条件
        gamePrizeLambdaQueryWrapper.in(GamePrizeEntity::getGameId, gameIdList)
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        List<GamePrizeEntity> gamePrizeList = baseMapper.selectList(gamePrizeLambdaQueryWrapper);
        log.info("批量查询游戏奖品完成。isEmpty={}", gamePrizeList);
        return gamePrizeList;
    }

    @Override
    public List<NameValue<String>> getSimpleGamePrizeList(Long gameId) {

        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gamePrizeLambdaQueryWrapper.select(GamePrizeEntity::getId, GamePrizeEntity::getPrizeName);
        // 匹配条件
        gamePrizeLambdaQueryWrapper.eq(GamePrizeEntity::getGameId, gameId)
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        List<GamePrizeEntity> gamePrizeList = baseMapper.selectList(gamePrizeLambdaQueryWrapper);
        // 数据封装
        return gamePrizeList.stream()
                .map(gamePrize -> new NameValue<>(gamePrize.getPrizeName(), gamePrize.getId().toString()))
                .collect(Collectors.toList());
    }

    @Override
    public Integer getNextSort(Long gameId) {
        Integer sort = baseMapper.getMaxSort(gameId, CommonEnum.ZERO.getValue());
        if (sort == null) {
            sort = 0;
        }
        return sort + 1;
    }

    @Override
    public Integer getTotalProbability(Long gameId) {
        Integer totalProbability = baseMapper.sumProbability(gameId, CommonEnum.ZERO.getValue(), CommonEnum.ZERO.getValue());
        if (totalProbability == null) {
            totalProbability = 0;
        }
        return totalProbability;
    }

    @Override
    public Map<Long, String> getPrizeNameMap(Set<Long> prizeIdSet) {
        if (CollectionUtils.isEmpty(prizeIdSet)) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gamePrizeLambdaQueryWrapper.select(GamePrizeEntity::getId, GamePrizeEntity::getPrizeName);
        // 匹配条件
        gamePrizeLambdaQueryWrapper.in(GamePrizeEntity::getId, prizeIdSet);
        // 查询数据
        List<GamePrizeEntity> gamePrizeList = baseMapper.selectList(gamePrizeLambdaQueryWrapper);
        // 数据封装
        return gamePrizeList.stream().collect(Collectors.toMap(GamePrizeEntity::getId, GamePrizeEntity::getPrizeName));
    }

    @Override
    public void updateGamePrize(GamePrizeVo gamePrizeVo) {
        // 判断是否允许插入
        GamePo gamePo = gameService.getGamePo(gamePrizeVo.getGameId());
        if (gamePo.getStatus().equals(CommonEnum.ZERO.getValue())) {
            log.warn("游戏已经开始，不可以修改奖品数据。 gameId={} {}", gamePrizeVo.getGameId(), gamePo);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏已经开始，不可以修改奖品数据。");
        }

        LambdaQueryWrapper<GamePrizeEntity> gamePrizeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        gamePrizeLambdaQueryWrapper.select(GamePrizeEntity::getPrizeName, GamePrizeEntity::getPrizeValue,
                GamePrizeEntity::getPrizeTotalNum, GamePrizeEntity::getProbability, GamePrizeEntity::getSort);
        // 匹配条件
        gamePrizeLambdaQueryWrapper.eq(GamePrizeEntity::getId, gamePrizeVo.getId())
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据
        List<GamePrizeEntity> gamePrizeList = baseMapper.selectList(gamePrizeLambdaQueryWrapper);
        if (gamePrizeList.isEmpty()) {
            log.info("游戏奖品数据为空。id={}", gamePrizeVo.getId());
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏奖品数据不存在，请确认");
        }
        GamePrizeEntity _gamePrize = gamePrizeList.get(0);

        // 获取正在保存游戏奖品的用户主键
        Long optUserId = SecurityUtils.getUserId();
        Date date = new Date();

        GamePrizeEntity gamePrize = new GamePrizeEntity();
        // 属性赋值
        gamePrize.setId(gamePrizeVo.getId())
                .setPrizeName(gamePrizeVo.getPrizeName())
                .setPrizeValue(gamePrizeVo.getPrizeValue())
                .setPrizeTotalNum(gamePrizeVo.getPrizeTotalNum())
                .setPrizeUseNum(0)
                .setProbability(gamePrizeVo.getProbability())
                .setSort(gamePrizeVo.getSort())
                .setUpdateTime(date)
                .setUpdateUser(optUserId)
                .setRemark(gamePrizeVo.getRemark());
        // 插入数据
        baseMapper.updateById(gamePrize);
        log.info("游戏奖品数据修改完成");

        asyncService.execute(() -> {
            boolean bool = false;
            // 记录新增奖品流水
            StringBuilder sb = new StringBuilder();
            sb.append("修改游戏奖品 ");
            if (!_gamePrize.getPrizeName().equals(gamePrize.getPrizeName())) {
                sb.append("奖品名称（【").append(_gamePrize.getPrizeName()).append("】改成【").append(gamePrize.getPrizeName()).append("】）");
            }
            if (!_gamePrize.getPrizeValue().equals(gamePrize.getPrizeValue())) {
                sb.append("具体奖品值（【").append(_gamePrize.getPrizeValue()).append("】改成【").append(gamePrize.getPrizeValue()).append("】）");
            }
            if (!_gamePrize.getPrizeTotalNum().equals(gamePrize.getPrizeTotalNum())) {
                sb.append("奖品总数（【").append(_gamePrize.getPrizeTotalNum()).append("】改成【").append(gamePrize.getPrizeTotalNum()).append("】）");
            }
            if (!_gamePrize.getProbability().equals(gamePrize.getProbability())) {
                sb.append("中奖概率（【").append(_gamePrize.getProbability()).append("】改成【").append(gamePrize.getProbability()).append("】）");
                bool = true;
            }
            if (!_gamePrize.getSort().equals(gamePrize.getSort())) {
                sb.append("排序等级（【").append(_gamePrize.getSort()).append("】改成【").append(gamePrize.getSort()).append("】）");
            }
            // 记录奖品流水
            gamePrizeFlowService.saveGamePrizeFlow(gamePrize.getId(), "修改奖品", sb.toString(), optUserId);

            if (bool) {
                // 游戏奖品概率变更，清理奖品池
                gameService.updatePrizePoolFlag(gamePrizeVo.getGameId(), GameEnum.NO_PRIZE_POOL.getValue(), optUserId);
            }
        });
    }

    @Override
    public void updateGamePrizeStatus(UpdateGamePrizeStatusVo updateStatusVo) {
        // 判断是否允许插入
        GamePo gamePo = gameService.getGamePo(updateStatusVo.getGameId());
        if (gamePo.getStatus().equals(CommonEnum.ZERO.getValue())) {
            log.warn("游戏已经开始，不可以修改奖品状态。 gameId={} {}", updateStatusVo.getGameId(), gamePo);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏已经开始，不可以修改奖品数据。");
        }
        // 获取正在更新游戏奖品状态的用户主键
        Long optUserId = SecurityUtils.getUserId();

        LambdaUpdateWrapper<GamePrizeEntity> gamePrizeLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 更新字段
        gamePrizeLambdaUpdateWrapper.set(GamePrizeEntity::getStatus, updateStatusVo.getStatus())
                .set(GamePrizeEntity::getUpdateTime, new Date())
                .set(GamePrizeEntity::getUpdateUser, optUserId);
        // 匹配条件
        gamePrizeLambdaUpdateWrapper.in(GamePrizeEntity::getId, updateStatusVo.getIdList())
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 更新数据
        int count = baseMapper.update(null, gamePrizeLambdaUpdateWrapper);
        log.info("游戏奖品状态更新完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "游戏奖品状态更新失败，请确认。");
        }

        asyncService.execute(() -> {
            // 记录新增奖品流水
            StringBuilder sb = new StringBuilder("修改游戏奖品状态 ");
            CommonEnum statusEnum = CommonEnum.getStatusEnum(updateStatusVo.getStatus());
            if (statusEnum != null) {
                sb.append("新状态 【").append(statusEnum.getName()).append('】');
            }
            // 记录奖品流水
            gamePrizeFlowService.batchSaveGamePrizeFlow(updateStatusVo.getIdList(), "修改奖品", sb.toString(), optUserId);

            // 游戏奖品概率变更，清理奖品池
            gameService.updatePrizePoolFlag(updateStatusVo.getGameId(), GameEnum.NO_PRIZE_POOL.getValue(), optUserId);
        });

    }

    @Override
    public void addUseNum(Long prizeId) {
        // 增加游戏奖品使用次数
        int count = baseMapper.addUseNum(prizeId, new Date());
        log.info("增加游戏奖品使用次数完成。count={}", count);
    }

    @Override
    public void deleteGamePrize(DeleteGamePrizeVo deleteGamePrizeVo) {
        // 判断是否允许插入
        GamePo gamePo = gameService.getGamePo(deleteGamePrizeVo.getGameId());
        if (gamePo.getStatus().equals(CommonEnum.ZERO.getValue())) {
            log.warn("游戏已经开始，不可以删除奖品数据。gameId={} {}", deleteGamePrizeVo.getGameId(), gamePo);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "游戏已经开始，不可以删除奖品。");
        }
        // 获取正在删除游戏奖品的用户主键
        Long optUserId = SecurityUtils.getUserId();

        LambdaUpdateWrapper<GamePrizeEntity> gamePrizeLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 更新字段
        gamePrizeLambdaUpdateWrapper.set(GamePrizeEntity::getDeleteFlag, CommonEnum.ONE.getValue())
                .set(GamePrizeEntity::getUpdateTime, new Date())
                .set(GamePrizeEntity::getUpdateUser, optUserId);
        // 匹配条件
        gamePrizeLambdaUpdateWrapper.in(GamePrizeEntity::getId, deleteGamePrizeVo.getIdList())
                .eq(GamePrizeEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 更新数据
        int count = baseMapper.update(null, gamePrizeLambdaUpdateWrapper);
        log.info("删除游戏奖品数据完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REFRESH.getCode(), "删除游戏奖品失败，请确认。");
        }

        asyncService.execute(() -> {
            // 记录新增奖品流水
            String title = "删除游戏奖品";
            // 记录奖品流水
            gamePrizeFlowService.batchSaveGamePrizeFlow(deleteGamePrizeVo.getIdList(), title, "", optUserId);

            // 游戏奖品概率变更，清理奖品池
            gameService.updatePrizePoolFlag(deleteGamePrizeVo.getGameId(), GameEnum.NO_PRIZE_POOL.getValue(), optUserId);
        });
    }
}